﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity.Core;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Transactions;
using System.Web;
using System.Web.Configuration;
using System.Web.Services;
using Sovigaz.DataProvider;
using Utilities;

namespace Sovigaz.WebService
{
    /// <summary>
    /// Summary description for SovigazService
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]
    public class SovigazService : System.Web.Services.WebService
    {
        private const int _sovigaz = 1;
        readonly SovigazDbContext _context = new SovigazDbContext();

        private IEnumerable<DeliveryPlanLineComplex> GetDeliveryPlanLine(int deliveryPlanID)
        {
            var deliveryPlanLines = _context.DeliveryPlanLines
                .Join(_context.DeliveryPlans, dpl => dpl.DeliveryPlanID, dp => dp.DeliveryPlanID, (dpl, dp) => new { dpl, dp })
                .Join(_context.OrderLines, p => p.dpl.OrderLineID, ol => ol.OrderLineID, (p, ol) => new { p.dpl, p.dp, ol })
                .Join(_context.Orders, p => p.ol.OrderID, o => o.OrderID, (p, o) => new { p.dpl, p.dp, p.ol, o })
                .Join(_context.Partners, p => p.o.PartnerID, pt => pt.PartnerID, (p, pt) => new { p.dpl, p.dp, p.ol, p.o, pt })
                .Join(_context.Categories, p => p.ol.CategoryID, c => c.CategoryID, (p, c) => new { p.dpl, p.dp, p.ol, p.o, p.pt, c })
                .Where(p => p.dp.DeliveryPlanID == deliveryPlanID && !p.dp.IsDeleted && !p.dpl.IsDeleted)
                .Select(p => new DeliveryPlanLineComplex
                {
                    DeliveryPlanLineID = p.dpl.DeliveryPlanLineID,
                    DeliveryPlanID = p.dpl.DeliveryPlanID,
                    PartnerID = p.pt.PartnerID,
                    PartnerName = p.pt.PartnerName,
                    OrderLineID = p.dpl.OrderLineID,
                    OrderID = p.o.OrderID,
                    CategoryID = p.ol.CategoryID,
                    CategoryName = p.c.CategoryName,
                    Size = p.ol.Size,
                    Capacity = p.ol.Capacity,
                    PlanQty = p.dpl.PlanQty,
                    ShippedQty = p.dpl.ShippedQty,
                    Description = p.dpl.Description
                }).ToList();

            return deliveryPlanLines;
        }

        [WebMethod(Description = "Đăng nhập hệ thống")]
        public bool Login(string username, string password, string sitemapID)
        {
            return true;
        }

        [WebMethod(Description = "Lấy danh sách kế hoạch giao hàng của ngày hiện tại và chưa được xuất đi giao")]
        public List<DeliveryPlanComplex> GetDeliveryPlan(DateTime date)
        {
            string status = DeliveryPlanStatus.N.ToString();
            var deliveryPlans = _context.DeliveryPlans.Where(p => p.Date == date && !p.IsDeleted && p.Status == status)
                .Join(_context.Users, dp => dp.UserID, u => u.UserID, (dp, u) => new { dp, u })
                .Select(p => new DeliveryPlanComplex
                {
                    DeliveryPlanID = p.dp.DeliveryPlanID,
                    LicensePlate = p.dp.LicensePlate,
                    FullName = p.u.FullName
                }).ToList();

            return deliveryPlans;
        }

        [WebMethod(Description = "Lấy chi tiết danh sách kế hoạch giao hàng của ngày hiện tại và chưa được xuất đi giao")]
        public List<DeliveryPlanLineComplex> GetDeliveryPlanLineToIssue(DateTime date)
        {
            string status = DeliveryPlanStatus.N.ToString();
            var deliveryPlanLines = _context.DeliveryPlans.Where(p => p.Date == date && !p.IsDeleted && p.Status == status)
                .Join(_context.DeliveryPlanLines,
                    dp => new { Key1 = dp.DeliveryPlanID, Key2 = true },
                    dpl => new { Key1 = dpl.DeliveryPlanID, Key2 = !dpl.IsDeleted }, (dp, dpl) => new { dp, dpl })
                .Join(_context.OrderLines, p => p.dpl.OrderLineID, ol => ol.OrderLineID, (p, ol) => new { p.dpl, p.dp, ol })
                .Join(_context.Orders, p => p.ol.OrderID, o => o.OrderID, (p, o) => new { p.dpl, p.dp, p.ol, o })
                .Join(_context.Partners, p => p.o.PartnerID, pt => pt.PartnerID, (p, pt) => new { p.dpl, p.dp, p.ol, p.o, pt })
                .Join(_context.Categories, p => p.ol.CategoryID, c => c.CategoryID, (p, c) => new { p.dpl, p.dp, p.ol, p.o, p.pt, c })
                .Select(p => new DeliveryPlanLineComplex
                {
                    DeliveryPlanLineID = p.dpl.DeliveryPlanLineID,
                    DeliveryPlanID = p.dpl.DeliveryPlanID,
                    PartnerID = p.pt.PartnerID,
                    PartnerName = p.pt.PartnerName,
                    OrderID = p.o.OrderID,
                    OrderLineID = p.dpl.OrderLineID,
                    CategoryID = p.ol.CategoryID,
                    CategoryName = p.c.CategoryName,
                    Size = p.ol.Size,
                    Capacity = p.ol.Capacity,
                    PlanQty = p.dpl.PlanQty,
                    ShippedQty = p.dpl.ShippedQty,
                    Description = p.dpl.Description
                }).ToList();

            return deliveryPlanLines;
        }

        [WebMethod(Description = "Lấy chi tiết danh sách kế hoạch giao hàng")]
        public List<DeliveryPlanLineComplex> GetDeliveryPlanLineToDelivery(int deliveryPlanID)
        {
            var deliveryPlanLines = _context.DeliveryPlanLines.Where(p => p.DeliveryPlanID == deliveryPlanID)
                .Join(_context.OrderLines, dpl => dpl.OrderLineID, ol => ol.OrderLineID, (dpl, ol) => new { dpl, ol })
                .Join(_context.Orders, p => p.ol.OrderID, o => o.OrderID, (p, o) => new { p.dpl, p.ol, o })
                .Join(_context.Partners, p => p.o.PartnerID, pt => pt.PartnerID, (p, pt) => new { p.dpl, p.ol, p.o, pt })
                .Join(_context.Categories, p => p.ol.CategoryID, c => c.CategoryID, (p, c) => new { p.dpl, p.ol, p.o, p.pt, c })
                .Select(p => new DeliveryPlanLineComplex
                {
                    DeliveryPlanLineID = p.dpl.DeliveryPlanLineID,
                    DeliveryPlanID = p.dpl.DeliveryPlanID,
                    PartnerID = p.pt.PartnerID,
                    PartnerName = p.pt.PartnerName,
                    OrderID = p.o.OrderID,
                    OrderLineID = p.dpl.OrderLineID,
                    CategoryID = p.ol.CategoryID,
                    CategoryName = p.c.CategoryName,
                    Size = p.ol.Size,
                    Capacity = p.ol.Capacity,
                    PlanQty = p.dpl.PlanQty,
                    ShippedQty = p.dpl.ShippedQty,
                    Description = p.dpl.Description
                }).ToList();

            return deliveryPlanLines;
        }

        [WebMethod(Description = "Lấy chi tiết từng chai đã được xuất lên xe theo kế hoạch giao hàng")]
        public List<InOutLineComplex> GetInOutLineToDelivery(int deliveryPlanID)
        {
            return _context.InOuts.Where(p => p.DeliveryPlanID == deliveryPlanID)
                .Join(_context.InOutLines, io => io.InOutID, iol => iol.InOutID, (io, iol) => iol)
                .Join(_context.Products, iol => iol.ProductID, p => p.ProductID, (iol, p) => new { iol, p })
                .Select(p => new InOutLineComplex()
                {
                    InOutLineID = p.iol.InOutLineID,
                    InOutID = p.iol.InOutID,
                    ProductID = p.p.ProductID,
                    ProductCode = p.p.ProductCode,
                    CategoryID = p.p.CategoryID,
                    Size = p.p.Size,
                    OrderID = p.iol.OrderID,
                    PartnerID = p.iol.PartnerID,
                    Status = p.iol.Status
                }).ToList();
        }

        [WebMethod(Description = "Lấy danh sách sản phẩm dựa trên barcode đã quét khi giao hàng")]
        public List<ProductComplex> GetProductToIssue(string[] barcodeArr)
        {
            var productList = new List<ProductComplex>();
            foreach (var b in barcodeArr)
            {
                string barcode = b.ToLower();

                int productID = ConvertUtility.IntParse(barcode.Replace("ts", String.Empty).Replace("tc", String.Empty));
                var tmp = _context.Products.Join(_context.Categories, p => p.CategoryID, c => c.CategoryID, (p, c) => new { p, c })
                    .FirstOrDefault(p => p.p.ProductID == productID && !p.p.IsDeleted);
                if (tmp != null)
                {
                    var product = new ProductComplex
                    {
                        ProductID = tmp.p.ProductID,
                        LotID = tmp.p.LotID,
                        CategoryID = tmp.c.CategoryID,
                        CategoryName = tmp.c.CategoryName,
                        PartnerID = tmp.p.PartnerID,
                        ProductCode = tmp.p.ProductCode,
                        Manufacture = tmp.p.Manufacture,
                        Symbol = tmp.p.Symbol,
                        Weight = tmp.p.Weight,
                        Volume = tmp.p.Volume,
                        Size = tmp.p.Size
                    };

                    productList.Add(product);
                }
            }

            return productList;
        }

        [WebMethod(Description = "Lấy danh sách sản phẩm dựa trên barcode đã quét khi nhận hàng")]
        public List<ProductComplex> GetProductToReceive(string[] barcodeArr)
        {
            var productList = new List<ProductComplex>();
            foreach (var b in barcodeArr)
            {
                string[] barcode = b.ToLower().Split('-');
                //// đối với trường hợp nhập barcode
                if (barcode[0].StartsWith("ts") || barcode[0].StartsWith("tc"))
                {
                    int productID = ConvertUtility.IntParse(barcode[0].Replace("ts", String.Empty).Replace("tc", String.Empty));
                    var tmp = _context.Products.Join(_context.Categories, p => p.CategoryID, c => c.CategoryID, (p, c) => new { p, c })
                        .FirstOrDefault(p => p.p.ProductID == productID && !p.p.IsDeleted);

                    var product = new ProductComplex
                    {
                        ProductID = tmp.p.ProductID,
                        LotID = tmp.p.LotID,
                        CategoryID = tmp.c.CategoryID,
                        CategoryName = tmp.c.CategoryName,
                        PartnerID = tmp.p.PartnerID,
                        ProductCode = tmp.p.ProductCode,
                        Manufacture = tmp.p.Manufacture,
                        Symbol = tmp.p.Symbol,
                        Weight = tmp.p.Weight,
                        Volume = tmp.p.Volume,
                        Size = tmp.p.Size,
                        IsEmpty = !ConvertUtility.BoolParse(barcode[1])
                    };

                    productList.Add(product);
                }
                else //// đối với trường hợp nhập mã chai
                {
                    var tmp = _context.Products.Join(_context.Categories, p => p.CategoryID, c => c.CategoryID, (p, c) => new { p, c })
                        .Where(p => p.p.ProductCode.ToLower() == barcode[0] && !p.p.IsDeleted).ToList();
                    if (tmp.Count == 1)
                    {
                        var product = new ProductComplex
                        {
                            ProductID = tmp[0].p.ProductID,
                            LotID = tmp[0].p.LotID,
                            CategoryID = tmp[0].c.CategoryID,
                            CategoryName = tmp[0].c.CategoryName,
                            PartnerID = tmp[0].p.PartnerID,
                            ProductCode = tmp[0].p.ProductCode,
                            Manufacture = tmp[0].p.Manufacture,
                            Symbol = tmp[0].p.Symbol,
                            Weight = tmp[0].p.Weight,
                            Volume = tmp[0].p.Volume,
                            Size = tmp[0].p.Size,
                            IsEmpty = !ConvertUtility.BoolParse(barcode[1])
                        };

                        productList.Add(product);
                    }
                    else
                    {
                        //// TODO: cho phép chọn chai trong trường hợp có hơn 2 mã
                    }
                }
            }

            return productList;
        }

        [WebMethod(Description = "Lấy thông tin phiếu điều xe dựa vào tài xế và biển số xe")]
        public Command GetCommand(DateTime date, string userName, string licensePlate)
        {
            return _context.Users.Where(p => p.Username == userName)
                .Join(_context.Commands,
                    u => new { Key1 = u.UserID, Key2 = licensePlate },
                    c => new { Key1 = c.UserID, Key2 = c.LicensePlate }, (u, c) => c)
                .FirstOrDefault();
        }

        [WebMethod(Description = "Hoàn thành xuất hàng theo kế hoạch lên xe")]
        public void CompleteExportBasePlan(int userID, int deliveryPlanID, List<ProductComplex> products)
        {
            using (var scope = new TransactionScope())
            {
                var deliveryPlan = _context.DeliveryPlans.Find(deliveryPlanID);
                var deliveryPlanLines = GetDeliveryPlanLine(deliveryPlanID);

                //// cập nhật trạng thái kế hoạch giao hàng "Đã hoàn thành"
                deliveryPlan.Status = DeliveryPlanStatus.C.ToString();

                //// tạo phiếu xuất kho có trạng thái đang giao
                var inout = new InOut
                {
                    DeliveryPlanID = deliveryPlanID,
                    Date = DateTime.Today,
                    Type = InOutType.I.ToString(),
                    Status = deliveryPlan.DeliveryType == DeliveryPlanType.SO.ToString() ? InOutStatus.S.ToString() : InOutStatus.C.ToString(),
                    Description = deliveryPlan.Description
                };

                _context.InOuts.Add(inout);

                _context.SaveChanges(userID);

                //// tạo chi tiết phiếu xuất kho theo kế hoạch giao hàng
                foreach (var dpl in deliveryPlanLines)
                {
                    var scannedProduct = products.Where(p => p.CategoryID == dpl.CategoryID && p.Size == dpl.Size).ToList();
                    for (int i = 0; i < scannedProduct.Count; i++)
                    {
                        var ioLine = new InOutLine
                        {
                            InOutID = inout.InOutID,
                            ProductID = scannedProduct[i].ProductID,
                            OrderID = dpl.OrderID,
                            PartnerID = dpl.PartnerID,
                            Status = deliveryPlan.DeliveryType == DeliveryPlanType.SO.ToString() ? InOutStatus.S.ToString() : InOutStatus.C.ToString(),
                        };

                        _context.InOutLines.Add(ioLine);

                        scannedProduct.RemoveAt(i);
                        i--;

                        dpl.ShippedQty++;

                        if (dpl.ShippedQty == dpl.PlanQty)
                            break;
                    }

                    //// cập nhật lại vị trí chai hiện tại đang ở đâu
                    if (deliveryPlan.DeliveryType == DeliveryPlanType.IN.ToString())
                    {
                        string productID = String.Join(",", scannedProduct.Select(p => p.ProductID));

                        _context.Database.SqlQuery<RolePermission>("sp_Product_Update_Partner @ProductID, @PartnerID"
                            , new SqlParameter { ParameterName = "ProductID", Value = productID }
                            , new SqlParameter { ParameterName = "PartnerID", Value = dpl.PartnerID }).FirstOrDefault();
                    }
                }

                _context.SaveChanges(userID);

                scope.Complete();
            }
        }

        [WebMethod(Description = "Hoàn thành giao hàng tại KH")]
        public void CompleteDeliveryAtPartner(int userID, int commandID, int partnerID, List<int> productID)
        {
            int inoutID;

            using (var scope = new TransactionScope())
            {
                var command = _context.Commands.Find(commandID);

                //// cập nhật hoặc tạo mới chi tiết lệnh điều xe để cập nhật số lượng thực giao, số lượng nhận về.
                var commandLine = _context.CommandLines.First(p => p.CommandID == commandID && p.PartnerID == partnerID);
                commandLine.ShippedQty = productID.Count;
                commandLine.ReceivedFullQty = commandLine.PlanQty - productID.Count;
                commandLine.Status = CommandStatus.C.ToString();

                //// lấy chi tiết xuất kho của kế hoạch giao hàng tương ứng với khách hàng
                var inoutLines = _context.InOuts.Where(p => p.DeliveryPlanID == command.DeliveryPlanID && !p.IsDeleted)
                    .Join(_context.InOutLines,
                        io => new { Key1 = io.InOutID, Key2 = partnerID },
                        iol => new { Key1 = iol.InOutID, Key2 = iol.PartnerID }, (io, iol) => new { iol })
                    .Select(p => p.iol).ToList();

                inoutID = inoutLines[0].InOutID;

                //// xóa những chai không được giao
                foreach (var iol in inoutLines.Where(p => !productID.Exists(c => c == p.ProductID)))
                {
                    _context.InOutLines.Remove(iol);
                }

                //// cập nhật lại trạng thái các chi tiết đã được giao
                foreach (var iol in inoutLines)
                {
                    iol.Status = InOutStatus.C.ToString();
                }

                //// thêm mới những chai được giao vào Split
                foreach (var id in productID)
                {
                    var commandLineSplit = new CommandLineSplit
                    {
                        CommandID = commandID,
                        PartnerID = partnerID,
                        ProductID = id,
                        Type = CommandLineSplitType.I.ToString()
                    };

                    _context.CommandLineSplits.Add(commandLineSplit);
                }

                _context.SaveChanges(userID);

                scope.Complete();
            }

            //// cập nhật lại trạng thái lệnh điều xe
            _context.Database.SqlQuery<Command>("sp_Command_Update_Status @CommandID"
                , new SqlParameter { ParameterName = "CommandID", Value = commandID }).FirstOrDefault();

            //// cập nhật lại trạng thái phiếu giao hàng
            _context.Database.SqlQuery<InOut>("sp_InOut_Update_Status @InOutID"
               , new SqlParameter { ParameterName = "InOutID", Value = inoutID }).FirstOrDefault();
        }

        [WebMethod(Description = "Hoàn thành nhận hàng tại kho Sovigaz")]
        public void CompleteReceiveAtSovigaz(int userID, List<ProductComplex> products)
        {
            using (var scope = new TransactionScope())
            {
                //// tạo phiếu nhập kho
                var inout = new InOut
                {
                    Date = DateTime.Today,
                    Type = InOutType.R.ToString(),
                    Status = InOutStatus.C.ToString()
                };

                _context.InOuts.Add(inout);

                foreach (var pro in products)
                {
                    var ioLine = new InOutLine
                    {
                        InOutID = inout.InOutID,
                        ProductID = pro.ProductID,
                        PartnerID = _sovigaz, //// Default company Sovigaz
                        Status = InOutStatus.C.ToString()
                    };

                    _context.InOutLines.Add(ioLine);
                }

                _context.SaveChanges(userID);

                scope.Complete();
            }
        }

        [WebMethod(Description = "Hoàn thành nhận hàng tại KH")]
        public void CompleteReceiveAtPartner(int commandID, int partnerID, List<int> productID)
        {
            using (var scope = new TransactionScope())
            {
                var commandLine = _context.CommandLines.First(p => p.CommandID == commandID && p.PartnerID == partnerID);
                commandLine.ReceivedEmptyQty += productID.Count;

                foreach (var id in productID)
                {
                    var commandLineSplit = new CommandLineSplit
                    {
                        CommandID = commandID,
                        PartnerID = partnerID,
                        ProductID = id,
                        Type = CommandLineSplitType.R.ToString()
                    };

                    _context.CommandLineSplits.Add(commandLineSplit);
                }

                _context.SaveChanges();

                scope.Complete();
            }
        }
    }
}
